#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>

#include "icar.h"
#include "icar_flat_msg.h"
#include "icar_log.h"
#include "icar_utils.h"


static const struct {
	const char *desc;
	int flag;
} icarmsg_flag[] = {
	{ "V1",     MSG_FLAG_V1},
	{ "V4",     MSG_FLAG_V4},
	{ "V8",     MSG_FLAG_V8},
	{ "S6",     MSG_FLAG_S6},
	{ "S17",    MSG_FLAG_S17},
	{ "S20",    MSG_FLAG_S20},
	{ "S32",    MSG_FLAG_S32 },
	{ "S81",    MSG_FLAG_S81},
	{ "R7",     MSG_FLAG_R7 },
	{ "R8",     MSG_FLAG_R8 },
	{ "I3",     MSG_FLAG_I3 },
	{ "I7",     MSG_FLAG_I7 },
	{ "I10",    MSG_FLAG_I10 },
	{ "I11",    MSG_FLAG_I11 },
	{ "I12",    MSG_FLAG_I12 },
	{ "I13",    MSG_FLAG_I13 },
	{ "I14",    MSG_FLAG_I14 },
	{ NULL,     0}
};

static const char *
lookup_msg_type(int flag)
{
	int i = 0;
	for (i = 0; i < ARRAY_SIZE(icarmsg_flag); i++)
	if (icarmsg_flag[i].flag == flag)
		return icarmsg_flag[i].desc;

	return NULL;
}

static int
lookup_msg_val(const char *desc)
{
	int i;
	for (i = 0; i < ARRAY_SIZE(icarmsg_flag); i++)
		if (strncasecmp(icarmsg_flag[i].desc, desc, strlen(icarmsg_flag[i].desc)) == 0)
			return icarmsg_flag[i].flag;

	return 0;
}



static int
icar_flat_command(uint8_t *dest, int flag, const char *product, size_t plen, int param, const char *value, size_t vlen)
{
	char data[1024];
	int count;
	time_t ts;
	struct tm *tm;
	const char *desc;

	memset(data, 0, sizeof(data));
	count = 0;
	time(&ts);
	tm = localtime(&ts);

	if (plen > 10) {
		icar_daemon(LOG_ERR, "Product is too long");
		return -1;
	}

	if (vlen > 500) {
		icar_daemon(LOG_ERR, "The length of parameters is too long");
		return -1;
	}

	if (!product) {
		icar_daemon(LOG_ERR, "The name of product could not be NULL!");
		return -1;
	}

	count += snprintf(data+count, sizeof(data)-count, "*%s,", product);
	count += snprintf(data+count, sizeof(data)-count, "0000000000,");

	if ((desc = lookup_msg_type(flag)) == NULL)
		return -1;

	count += snprintf(data+count, sizeof(data)-count, "%s,", desc);

	count += snprintf(data+count, sizeof(data)-count, "%02d%02d%02d,",
			tm->tm_hour, tm->tm_min, tm->tm_sec);


	if (flag == MSG_FLAG_S17 || flag == MSG_FLAG_S6 
			|| flag == MSG_FLAG_S20
			|| flag == MSG_FLAG_S32 ) {
		if ((sizeof(data) - count) < vlen || !value)
			return -1;
		count += snprintf(data+count, sizeof(data)-count, "%s#", value);
		goto send_msg;
	} else if (flag == MSG_FLAG_R7) {
		data[count-1] = '#';
		goto send_msg;
	} else if (flag == MSG_FLAG_R8) {
		if (sizeof(data) - count < vlen || !value)
			return -1;
		count += snprintf(data+count, sizeof(data)-count, "%s#", value);
		goto send_msg;
	} else if (flag == MSG_FLAG_I10 
			|| flag == MSG_FLAG_I11
			|| flag == MSG_FLAG_I12
			|| flag == MSG_FLAG_I13) {
		data[count-1] = '#';
		goto send_msg;
	}

	if (param < 0 || param > 99)
	{
		icar_daemon(LOG_ERR, "Error setup command format");
		return -1;
	}
	count += snprintf(data+count, sizeof(data)-count, "%02d", param);

	if (!value)
		count += snprintf(data+count, sizeof(data)-count, " #");
	else {
		if (sizeof(data) - count < vlen) {
			icar_daemon(LOG_ERR, "The value of parameters is too long");
			return -1;
		}
		count += snprintf(data+count, sizeof(data)-count, ",%s#", value);
	}

send_msg:
	data[count++] = icar_data_auth(data, count);

	count = icar_pkg_trans_add_head_tail(dest, data, count);

	if (count < 0)
	{
		icar_daemon(LOG_ERR, "Translate error or package error");
		return -1;
	}

	return count;
}

int 
flat_set_water_temp(uint8_t *dest, const char *pro, size_t plen, int temperature)
{
	char buf[VALUE_LEN] = { 0 };
	snprintf(buf, sizeof(buf), "%03d", temperature);
	return icar_flat_command(dest, MSG_FLAG_S81, pro, plen, 1, buf, strlen(buf));
}

int 
flat_set_motor_time(uint8_t *dest, const char *pro, size_t plen, int value)
{
	char buf[VALUE_LEN] = { 0 };
	snprintf(buf, sizeof(buf), "%02d", value);
	return icar_flat_command(dest, MSG_FLAG_S81, pro, plen, 2, buf, strlen(buf));
}

int
flat_set_speed(uint8_t *dest, const char *pro, size_t plen, int value)
{
	char buf[VALUE_LEN] = { 0 };
	snprintf(buf, sizeof(buf), "%03d", value);
	return icar_flat_command(dest, MSG_FLAG_S81, pro, plen, 3, buf, strlen(buf));
}

int
flat_set_voltage(uint8_t *dest, const char *pro, size_t plen, int value)
{
	char buf[VALUE_LEN] = { 0 };
	snprintf(buf, sizeof(buf), "%d", value);
	return icar_flat_command(dest, MSG_FLAG_S81, pro, plen, 4, buf, strlen(buf));
}

int
flat_set_obd_interval(uint8_t *dest, const char *pro, size_t plen, int value)
{
	char buf[VALUE_LEN] = { 0 };
	snprintf(buf, sizeof(buf), "%04d", value);
	return icar_flat_command(dest, MSG_FLAG_S81, pro, plen, 5, buf, strlen(buf));
}

int
flat_set_fault_interval(uint8_t *dest, const char *pro, size_t plen, int value)
{
	char buf[VALUE_LEN] = { 0 };
	snprintf(buf, sizeof(buf), "%04d", value);
	return icar_flat_command(dest, MSG_FLAG_S81, pro, plen, 6, buf, strlen(buf));
}

int
flat_set_accOff_interval(uint8_t *dest, const char *pro, size_t plen, int time, int interval)
{
	char buf[VALUE_LEN] = { 0 };
	snprintf(buf, sizeof(buf), "%03d,%03d", time, interval);
	return icar_flat_command(dest, MSG_FLAG_S81, pro, plen, 7, buf, strlen(buf));
}

int
flat_set_aOn_interval(uint8_t *dest, const char *pro, size_t plen, int time, int interval)
{
	char buf[VALUE_LEN] = { 0 };
	snprintf(buf, sizeof(buf), "%04d,%d", time, interval);
	return icar_flat_command(dest, MSG_FLAG_S17, pro, plen, 0, buf, strlen(buf));
}

int
flat_set_gps_reboot(uint8_t *dest, const char *pro, size_t plen)
{
	return icar_flat_command(dest, MSG_FLAG_S81, pro, plen, 8, NULL, 0);
}

int
flat_set_hard_reboot(uint8_t *dest, const char *pro, size_t plen)
{
	return icar_flat_command(dest, MSG_FLAG_S81, pro, plen, 9, NULL, 0);
}

int
flat_set_reset(uint8_t *dest, const char *pro, size_t plen)
{
	return icar_flat_command(dest, MSG_FLAG_S81, pro, plen, 10, NULL, 0);
}

int
flat_set_offset_distance(uint8_t *dest, const char *pro, size_t plen, size_t distance)
{
	char buf[VALUE_LEN] = { 0 };
	snprintf(buf, sizeof(buf), "%04d", distance);
	return icar_flat_command(dest, MSG_FLAG_S81, pro, plen, 12, buf, strlen(buf));
}

int
flat_set_owner_number(uint8_t *dest, const char *pro, size_t plen, const char *number, size_t nlen)
{
	char buf[VALUE_LEN] = { 0 };
	if (nlen >= VALUE_LEN)
		return -1;
	if (number)
		strncpy(buf, number, nlen);

	return icar_flat_command(dest, MSG_FLAG_S81, pro, plen, 13, buf, strlen(buf));
}

int
flat_set_sos_number(uint8_t *dest, const char *pro, size_t plen, const char *number, size_t nlen)
{
	char buf[VALUE_LEN] = { 0 };
	if (nlen >= VALUE_LEN)
		return -1;
	if (number)
		strncpy(buf, number, nlen);
	return icar_flat_command(dest, MSG_FLAG_S81, pro, plen, 14, buf, strlen(buf));
}

int
flat_set_sim_number(uint8_t *dest, const char *pro, size_t plen, const char *number, size_t nlen)
{
	char buf[VALUE_LEN] = { 0 };
	if (nlen >= VALUE_LEN)
		return -1;
	if (number)
		strncpy(buf, number, nlen);
	return icar_flat_command(dest, MSG_FLAG_S81, pro, plen, 30, buf, strlen(buf));
}

int
flat_calibrate_vehicle(uint8_t *dest, const char *pro,size_t plen, const char *value, size_t nlen)
{
	return icar_flat_command(dest, MSG_FLAG_S81, pro, plen, 8, value, nlen);
}

int
flat_clear_fault_alarm(uint8_t *dest, const char *pro, size_t plen)
{
	return icar_flat_command(dest, MSG_FLAG_R7, pro, plen, 0, NULL, 0);
}

int
flat_monitor(uint8_t *dest, const char *pro, size_t plen, const char *number, size_t nlen)
{
	return icar_flat_command(dest, MSG_FLAG_R8, pro, plen, 0, number, nlen);
}

int
flat_set_defence(uint8_t *dest, const char *pro, size_t plen, int value)
{
	char buf[VALUE_LEN] = { 0 };
	snprintf(buf, sizeof(buf), "%d", value);
	return icar_flat_command(dest, MSG_FLAG_S6, pro, plen, 0, buf, strlen(buf));
}

int
flat_oil_power(uint8_t *dest, const char *pro, size_t plen, int value)
{
	char buf[VALUE_LEN] = { 0 };
	snprintf(buf, sizeof(buf), "1,%d,30,3,30,3,10,3,3", value);
	return icar_flat_command(dest, MSG_FLAG_S20, pro, plen, 0, buf, strlen(buf));
}

int
flat_level_check(uint8_t *dest, const char *pro, size_t plen)
{
	return icar_flat_command(dest, MSG_FLAG_S81, pro, plen, 15, NULL, 0);
}

int
flat_mileage_calibrate(uint8_t *dest, const char *pro, size_t plen, size_t value)
{
	char buf[VALUE_LEN] = { 0 };
	snprintf(buf, sizeof(buf), "%x", value);
	return icar_flat_command(dest, MSG_FLAG_S32, pro, plen, 0, buf, strlen(buf));
}

int
flat_mail_phone_alarm(uint8_t *dest, const char *pro, size_t plen, int param, int value)
{
	char buf[VALUE_LEN] = { 0 };
	snprintf(buf,  sizeof(buf), "%d", value);
	return icar_flat_command(dest, MSG_FLAG_S81, pro,  plen, param, buf, strlen(buf));
}

int
flat_diagnose(uint8_t *dest, const char *pro, size_t plen)
{
	return icar_flat_command(dest, MSG_FLAG_I10, pro, plen, 0, NULL, 0);
}

int flat_check(uint8_t *dest, const char *pro, size_t plen)
{
	return icar_flat_command(dest, MSG_FLAG_I11, pro, plen, 0, NULL, 0);
}

int flat_query_fault(uint8_t *dest, const char *pro, size_t plen)
{
	return icar_flat_command(dest, MSG_FLAG_I12, pro, plen, 0, NULL, 0);
}

int flat_clean_fault(uint8_t *dest, const char *pro, size_t plen)
{
	return icar_flat_command(dest, MSG_FLAG_I13, pro, plen, 0, NULL, 0);
}

int flat_query_status(uint8_t *dest, const char *pro, size_t plen)
{
	return icar_flat_command(dest, MSG_FLAG_I14, pro, plen, 0, NULL, 0);
}

